﻿//
// Copyright (c) 2024 BPergaofeng
//
#include "BPerRtcReceive.h"


#include <bperutil/sys/BPerLog.h>
#include <bperutil/sys/BPerThread.h>

void g_rtcrecv_receiveAudio(void* user,BPerFrame *audioFrame){
	if(user==NULL) return;
	BPerRtcReceive* rtcHandle=(BPerRtcReceive*)user;
	rtcHandle->receiveAudio(audioFrame);
}
void g_rtcrecv_receiveVideo(void* user,BPerFrame *videoFrame){
	if(user==NULL) return;
	BPerRtcReceive* rtcHandle=(BPerRtcReceive*)user;
	rtcHandle->receiveVideo(videoFrame);
}

void g_rtcrecv_receiveMsg(void* user,BPerFrame *msgFrame){
	if(user==NULL) return;
	BPerRtcReceive* rtcHandle=(BPerRtcReceive*)user;
	rtcHandle->receiveMsg(msgFrame);

}
int32_t g_rtcrecv_sendRtcMessage(void* user,int puid,BPerRtcMessageType mess){
	if(user==NULL) return 1;
	BPerRtcReceive* rtcHandle=(BPerRtcReceive*)user;
	if(rtcHandle->m_recv->sendRtcMessage) rtcHandle->m_recv->sendRtcMessage(&rtcHandle->m_recv->peer,mess);
	return BPer_Ok;
}

BPerRtcReceive::BPerRtcReceive(BPerContext* pcontext,BPerSysMessageI* pmessage) {
	m_message=pmessage;
	m_context=pcontext;
	m_isStart = 0;
	m_out_videoBuffer = NULL;
	m_out_audioBuffer = NULL;
	m_isReceived = 0;
	m_loops = 0;
	m_headLen = 1; //pcontext->audio.audioDecoderType == 0 ? 2 : 1;
	m_recv = NULL;
    m_url=NULL;
	m_waitState = 0;
	bPer_thread_mutex_init(&m_lock,NULL);
	bPer_thread_cond_init(&m_cond_mess,NULL);

	m_context->sendRtcMessage.context=this;
	m_context->sendRtcMessage.sendRtcMessage=g_rtcrecv_sendRtcMessage;

}

BPerRtcReceive::~BPerRtcReceive() {
	disConnect();
	if (m_loops) {
		while (m_isStart) {
			bPer_usleep(1000);
		}
	}
	bPer_delete(m_recv);


	m_out_audioBuffer = NULL;
	m_out_videoBuffer = NULL;
	m_message=NULL;
	bPer_thread_mutex_destroy(&m_lock);
	bPer_thread_cond_destroy(&m_cond_mess);
    bPer_free(m_url);
}

void BPerRtcReceive::disConnect() {
	if (m_recv)
		m_recv->close(&m_recv->peer);
	stop();
	bPer_destroy_peerConnection(m_recv);
	bPer_free(m_recv);

}
void BPerRtcReceive::setBuffer(BPerAudioEncoderBuffer *al,BPerVideoDecoderBuffer *vl) {
	m_out_audioBuffer = al;
	m_out_videoBuffer = vl;
}

void BPerRtcReceive::setMediaConfig(int32_t puid, BPerAudioParam *audio,BPerVideoParam *video){

}

int32_t BPerRtcReceive::publishMsg(BPerFrame* msgFrame){
    if(m_recv) {
    	return m_recv->on_message(&m_recv->peer,msgFrame);
    }
	return 1;
}
int32_t BPerRtcReceive::receiveMsg(BPerFrame* msgFrame){


	return BPer_Ok;
}

void BPerRtcReceive::receiveAudio(BPerFrame *audioFrame) {
    if(audioFrame==NULL||!audioFrame->payload) return;
	m_out_audioBuffer->putPlayAudio(audioFrame);

}
void BPerRtcReceive::receiveVideo(BPerFrame *videoFrame) {
    if(videoFrame==NULL||videoFrame->payload==NULL) return;
    m_out_videoBuffer->putEVideo(videoFrame);
}

int32_t BPerRtcReceive::init(int32_t puid, char* localIp,
		char* server, int32_t pport, char* app, char* stream) {
	if (!m_recv) m_recv=(BPerPeerConnection*)calloc(sizeof(BPerPeerConnection),1);
	//memset(&m_recv->peer.streamconfig,0,sizeof(m_recv->peer.streamconfig));
	m_recv->peer.streamconfig.localPort = m_context->avinfo.rtc.rtcLocalPort;
	strcpy(m_recv->peer.streamconfig.remoteIp,server);
	m_recv->peer.streamconfig.remotePort = pport;
	strcpy(m_recv->peer.streamconfig.app,app);
	strcpy(m_recv->peer.streamconfig.stream,stream);
	m_recv->peer.streamconfig.uid = puid;
    m_recv->peer.streamconfig.streamDirection = BPerRecvonly;

	m_recv->peer.streamconfig.recvCallback.context=this;
	m_recv->peer.streamconfig.recvCallback.receiveAudio=g_rtcrecv_receiveAudio;
	m_recv->peer.streamconfig.recvCallback.receiveVideo=g_rtcrecv_receiveVideo;
	m_recv->peer.streamconfig.recvCallback.receiveMsg=g_rtcrecv_receiveMsg;

	m_recv->peer.streamconfig.recvCallback.context=this;

	memcpy(&m_recv->peer.streamconfig.rtcCallback,&m_context->rtcCallback,sizeof(BPerRtcCallback));
	m_recv->peer.avinfo=&m_context->avinfo;
	bPer_create_peerConnection(m_recv);
    m_recv->init(&m_recv->peer);
        m_recv->addAudioTrack(&m_recv->peer,BPer_AED_OPUS);
    m_recv->addVideoTrack(&m_recv->peer,BPer_VED_H264);
    m_recv->addTransceiver(&m_recv->peer,m_recv->peer.streamconfig.direction);
	return BPer_Ok;
}



int32_t BPerRtcReceive::init(int32_t puid,char* url){
    if (!m_recv) m_recv=(BPerPeerConnection*)calloc(sizeof(BPerPeerConnection),1);
    //memset(&m_recv->peer.streamconfig,0,sizeof(m_recv->peer.streamconfig));
    m_recv->peer.streamconfig.localPort = m_context->avinfo.rtc.rtcLocalPort++;

    m_recv->peer.streamconfig.uid = puid;
    m_recv->peer.streamconfig.streamDirection = BPerRecvonly;

    m_recv->peer.streamconfig.recvCallback.context=this;
    m_recv->peer.streamconfig.recvCallback.receiveAudio=g_rtcrecv_receiveAudio;
    m_recv->peer.streamconfig.recvCallback.receiveVideo=g_rtcrecv_receiveVideo;
    m_recv->peer.streamconfig.recvCallback.receiveMsg=g_rtcrecv_receiveMsg;

    m_recv->peer.streamconfig.recvCallback.context=this;

    memcpy(&m_recv->peer.streamconfig.rtcCallback,&m_context->rtcCallback,sizeof(BPerRtcCallback));
    m_recv->peer.avinfo=&m_context->avinfo;
    bPer_create_peerConnection(m_recv);
    m_recv->addAudioTrack(&m_recv->peer,BPer_AED_OPUS);
    m_recv->addVideoTrack(&m_recv->peer,BPer_VED_H264);
    m_recv->addTransceiver(&m_recv->peer,m_recv->peer.streamconfig.direction);
    int len=strlen(url);
    if(m_url==NULL) m_url=(char*)bPer_malloc(len+1);
    memcpy(m_url,url,len);
    m_url[len]=0;
    return BPer_Ok;
}


void BPerRtcReceive::stop() {
	m_loops = 0;
	if (m_recv)
		m_recv->close(&m_recv->peer);

	if (m_waitState) {
		bPer_thread_mutex_lock(&m_lock);
		bPer_thread_cond_signal(&m_cond_mess);
		bPer_thread_mutex_unlock(&m_lock);

	}
}
void BPerRtcReceive::run() {
	m_isStart = 1;
	startLoop();
	m_isStart = 0;
}
void BPerRtcReceive::startLoop() {
	bPer_reindex(m_out_audioBuffer);
	bPer_reindex(m_out_videoBuffer);
	m_loops = 1;
	m_isReceived = 1;
    int32_t err=m_url?m_recv->connectWhipWhepServer(&m_recv->peer,m_url):m_recv->connectSfuServer(&m_recv->peer);
    if (err!=BPer_Ok) {
		m_loops=0;
		if(m_message) m_message->failure(err);
	}else{
		if(m_message) m_message->success();
	}
    bPer_free(m_url);
	bPer_thread_mutex_lock(&m_lock);
	while (m_loops == 1) {
		m_waitState = 1;

		bPer_thread_cond_wait(&m_cond_mess, &m_lock);
		m_waitState = 0;
	}	            		//end while

	if (m_recv)
		m_recv->close(&m_recv->peer);
	m_isReceived = 0;
	bPer_thread_mutex_unlock(&m_lock);
}
